local CMD = require "game_proto"
local skynet = require "skynet"

local MJCONST =  require "const"
local TABLECONST = MJCONST.TABLECONST
local CHAIRCONST = MJCONST.CHAIRCONST
local PAICONST = MJCONST.PAICONST
local WIKTYPE = MJCONST.WIKTYPE

local Config = {FanJiangNum = 1}


local FANWAIFAN = {QINGYISE=0x0001,HAIDIHU=0x0002,HAIDIPAO=0x0004,GANGHUA=0x0008,GANGPAO=0x0010,QUANQIUREN=0x0020,QIANGGANGHU=0x0040,TIANHU=0x0080,DIHU=0x0100,MENQINIG=0x0200,QUANQIURENDIANPAO=0x0400,SHISANYAO=0x0800,ZIYISE=0x1000}
local HUTYPE = {HT_NULL=0, HT_PINGHU=1, HT_PENGPENGHU=0x2, HT_QIXIAODUI=0x4, HT_QIDADUI=0x8, HT_HAOQI=0xF, HT_CHAOHAOQI=0xF0, HT_SHISANYAO=0x10}


ChairAction = {}

local UserActions = {}

BufTool = {}
function BufTool.WriteOffset(len)
    local str = ''
    for i = 1, len do
        local usrAct = string.char(0) 
        str = str..usrAct
    end
    return str
end

local MainCmdId = CMD.Main_ClientAndGameSvr_TableModle

function UserActions:New(obj)
	obj = obj or {}
	setmetatable(obj, self)
	self.__index = self
	return obj
end

function UserActions:Reset()
	for i = 1, #self do
		self[i] = nil
	end
end

function UserActions:GetPackString()
    local buf = ''
	local num = #self
    buf = buf..string.pack('B', num)
	local hasHU = false
	for i = 1, num do
		local act = self[i]
        local oneTypeNum = 0
        if act.Type == WIKTYPE.WIK_LINE then 
            oneTypeNum = #act.tabChi    --多少种吃法
        end
		buf = buf..string.pack('BBB', act.Type, act.CardData, oneTypeNum)
        for i = 1, oneTypeNum do 
            buf = buf..string.pack('BB', act.tabChi[i].b, act.tabChi[i].a)   --chi
        end
        buf = buf..BufTool.WriteOffset((3 - oneTypeNum) * 2)   --chi
        buf = buf..BufTool.WriteOffset(32)  
		if act.Type == WIKTYPE.WIK_HU then hasHU = true end
	end
    buf = buf..BufTool.WriteOffset((CHAIRCONST.MAX_ACTION_SELECTTION - num) * 41)    --41是OneActionData的大小
    buf = buf..BufTool.WriteOffset(32)  
    return buf
end

function ChairAction:New(obj)
	obj = obj or {}
	setmetatable(obj, self)
	self.__index = self
	return obj
end

function ChairAction:ClearChair()
    self.tabCbCardIndex = {}
    self.tabCbOutCard = {}
    self.tabWeaveItem = {}
    self.tabUserAction = {}
    self.tabTingCardData={}
    self.tabToDo = {}
    self.HasDispatchXiPai = false
    self.tabLiaoLong = {}
    self.tabXiPai = {}
    UserActions:Reset()
    self:ResetLou()
end

function ChairAction:MakeReadyChair(tabFrame) 
    self:ClearChair()
    self:Init()
    self.tabFrame = tabFrame
end

function ChairAction:Quit()
    self:ClearChair()
    self.addr = nil
end

function ChairAction:RegisterFun()
    self.DoMsgList = {}
    self.DoMsgList[WIKTYPE.WIK_LINE]    =  {Type = WIKTYPE.WIK_LINE,    Func = self.DoChi}
    self.DoMsgList[WIKTYPE.WIK_PENG]    =  {Type = WIKTYPE.WIK_PENG,    Func = self.DoPeng}
    self.DoMsgList[WIKTYPE.WIK_ANGANG]  =  {Type = WIKTYPE.WIK_ANGANG,  Func = self.DoAnGang}
    self.DoMsgList[WIKTYPE.WIK_JIEGANG] =  {Type = WIKTYPE.WIK_JIEGANG, Func = self.DoJieGang}
    self.DoMsgList[WIKTYPE.WIK_JIAGANG] =  {Type = WIKTYPE.WIK_JIAGANG, Func = self.DoJiaGang}
    self.DoMsgList[WIKTYPE.WIK_DU]      =  {Type = WIKTYPE.WIK_JIAGANG, Func = self.DoJiaGang}
    self.DoMsgList[WIKTYPE.WIK_HU]      =  {Type = WIKTYPE.WIK_HU,      Func = self.DoHu}
    
    self.CANCELCMD = {}
    self.CANCELCMD[WIKTYPE.WIK_LINE]    = CMD.Sub_GameSvrToClient_TableModle_UserCancelChiOk
    self.CANCELCMD[WIKTYPE.WIK_PENG]    = CMD.Sub_GameSvrToClient_TableModle_UserCancelPengOk
    self.CANCELCMD[WIKTYPE.WIK_JIEGANG] = CMD.Sub_GameSvrToClient_TableModle_UserCancelPengOk
    self.CANCELCMD[WIKTYPE.WIK_JIAGANG] = CMD.Sub_GameSvrToClient_TableModle_UserCancelJiaGangOk
    self.CANCELCMD[WIKTYPE.WIK_ANGANG]  = CMD.Sub_GameSvrToClient_TableModle_UserCancelAnGangOk
    self.CANCELCMD[WIKTYPE.WIK_HU]      = CMD.Sub_GameSvrToClient_TableModle_UserCancelHu
end

function ChairAction:Init()
    self:RegisterFun()
	for i = 1, PAICONST.MAX_INDEX  do 
		self.tabCbCardIndex[i] = 0
	end
    self.tabUserAction = UserActions:New()
	self.tabCardVal = {}
end

function ChairAction:SendData(msg)
    send_data(self.addr, msg)
end

function ChairAction:SendDataInLua(subId, msg)
    local msgSend = string.pack('>I2>I2', MainCmdId, subId)
    if msg then msgSend = msgSend..msg end
    send_data(self.addr, msgSend)
end

function ChairAction:StartFaPai(wJu)
    local gameStartDataMsg = string.pack("<I2<I2<I2", wJu, self.tabFrame.Banker, self.tabFrame.Banker)
    gameStartDataMsg = gameStartDataMsg..self.tabUserAction:GetPackString()
    gameStartDataMsg = gameStartDataMsg..string.pack('b', 83)
    for i = 1, TABLECONST.NUM_HANDFULL do 
        gameStartDataMsg = gameStartDataMsg..string.pack('b', self.tabCardVal[i] or 0)
    end
    local strLogFapai = 'FaPai is '
    table.sort(self.tabCardVal)
    for i = 1, TABLECONST.NUM_HANDFULL do 
        strLogFapai = strLogFapai..string.format('%0x ', self.tabCardVal[i] or 0)
    end
    skynet.error(strLogFapai)
    self:SendDataInLua(CMD.Sub_GameSvrToClient_TableModle_NTGameStartData, gameStartDataMsg)
end

function ChairAction:OnDispatchCard(cbCardData, nLeftCardCount, permitOutCard)   --椅子摸牌
    if cbCardData ~= 0 then     
        local ind = MjLogic:ValToIndex(cbCardData)
        self.tabCbCardIndex[ind] = self.tabCbCardIndex[ind] + 1
    end
    if permitOutCard then 
        self:ResetLou()
        if self.tabFrame.LeftCardCount > 0 then    --摸最后一张牌时不许杠
            self:CanGang(cbCardData, WIKTYPE.WIK_ANGANG)
            self:CanGang(cbCardData, WIKTYPE.WIK_JIAGANG)
            self:CanGang(cbCardData, WIKTYPE.WIK_DU)    --是否可以笃（不要补牌）
        end
        self:CanHu(cbCardData)
        
        local str = ''
        local standCard = self:GetStandCard() 
		for i = 1, TABLECONST.NUM_HANDFULL do   --23个
			local val = standCard[i]
            str = str..string.format('%0x ', val or 0)
		end
        
    end
	
    local dispatchMsg = string.pack("I2B", self.UserChairID, cbCardData)
    dispatchMsg = dispatchMsg..self.tabUserAction:GetPackString()
    dispatchMsg = dispatchMsg..string.pack("I2", nLeftCardCount)
    
    self:SendDataInLua(CMD.Sub_GameSvrToClient_TableModle_DispatchCardToMe, dispatchMsg)
end

function ChairAction:AddHandCard(val)
    local ind = MjLogic:ValToIndex(val)
    self.tabCbCardIndex[ind] = self.tabCbCardIndex[ind] + 1
end

function ChairAction:OnOutCard(cbCardData)        --椅子出牌
	local ind = MjLogic:ValToIndex(cbCardData)
	self.tabCbCardIndex[ind] = self.tabCbCardIndex[ind] - 1
	self.tabCbOutCard[#self.tabCbOutCard + 1] = cbCardData
end


function ChairAction:OthersCardToMe(wOtherUserId, nLeftCardCount)
	local msg = string.pack('>I2>I2', MainCmdId, CMD.Sub_GameSvrToClient_TableModle_DispatchCardToOther)
    msg = msg..string.pack('I2B', wOtherUserId, nLeftCardCount)
	self:SendData(msg)
end

function ChairAction:UpdataTingData()
	self.tabTingCardData = MjLogic:IsTing(self.tabCbCardIndex, self.tabWeaveItem)
	local tingLen = #self.tabTingCardData.val
    local msg = string.pack('>I2>I2<B', MainCmdId, CMD.Sub_GameSvrToClient_TableModle_UpdateTingCardData, tingLen)
	if tingLen > 0 then
		for i = 1, #self.tabTingCardData.val do
            local v = string.pack('B', self.tabTingCardData.val[i])
            msg = msg..v
		end
        for i = 1, CHAIRCONST.MAX_TINGNUM - tingLen do 
            local v = string.pack('B', 0)
            msg = msg..v
        end
		self:SendData(msg)
	else
        for i = 1, CHAIRCONST.MAX_TINGNUM + 1 do 
            local v = string.pack('B', 0)
            msg = msg..v
        end    
		self:SendData(msg)
	end
end

function ChairAction:IsLouPeng(getData)
    if self.LouPeng then 
        if self.LouPeng[getData] then skynet.error(' Chair Id '..self.UserChairID..' LouPeng :'..getData) end
        return self.LouPeng[getData]
    end
    return false
end

function ChairAction:IsLouHu()
    if self.LouHu then skynet.error(' Chair Id '..self.UserChairID..' LouHu') end
	return self.LouHu or false
end

function ChairAction:CheckHu(getData)
	local cardIndex = DeepCopy(self.tabCbCardIndex)
	local bZiMo = true
	if MjLogic:GetHandCardNum(self.tabCbCardIndex) % 3 == 1 then 
		local index = MjLogic:ValToIndex(getData)
		cardIndex[index] = cardIndex[index] + 1
		bZiMo = false
	end 
	if #self.tabTingCardData == 0 or #self.tabTingCardData.val == 0 then return false end
	local bHu = false
	local type = 0
	for i = 1, #self.tabTingCardData.val do
		if self.tabTingCardData.val[i] == getData then
			bHu = true 
			type = self.tabTingCardData.type[i]
			break
		end 
	end 
	if not bHu then return false
	else return true, type end
end

function ChairAction:CanHu(cbCardData, provider)
    local bHu, type = self:CheckHu(cbCardData)
	if bHu then 
        if self.tabFrame.PingHuZiMo and type == HUTYPE.HT_PINGHU and provider then return false end   --平胡需自摸
		local tabAction = {}
		tabAction.Type = WIKTYPE.WIK_HU
		tabAction.CardData = cbCardData
        tabAction.Provider = provider
		self.tabUserAction[#self.tabUserAction + 1] = tabAction
		return true
	end
	return false
end

function ChairAction:CanGang(getData, type, Provider)       --加了该张牌,可能有多个暗杠的牌
	if type == WIKTYPE.WIK_ANGANG then 
		local gang = {}
		for i = 1, PAICONST.MAX_INDEX do 
			if self.tabCbCardIndex[i] > 3 then 
				local val = MjLogic:IndexToVal(i)
				local tabAction = {}
				tabAction.CardData = val
				tabAction.Type = WIKTYPE.WIK_ANGANG
				self.tabUserAction[#self.tabUserAction + 1] = tabAction
				gang[#gang + 1] = val
			end
		end
		return #gang > 0, gang
	elseif type == WIKTYPE.WIK_JIEGANG and getData > 0 then
		local index = MjLogic:ValToIndex(getData)
		local num = self.tabCbCardIndex[index]
		local tabAction = {}
		tabAction.Type = type
		tabAction.CardData = getData
        tabAction.Provider = Provider
		local bJieGang = false
		if num == 3 then 
			self.tabUserAction[#self.tabUserAction + 1] = tabAction
			bJieGang = true
		end
		return bJieGang
    elseif type == WIKTYPE.WIK_JIAGANG  and getData > 0 then 
        for i = 1, #self.tabWeaveItem do
            local weaveItem = self.tabWeaveItem[i]
            if weaveItem.Kind == WIKTYPE.WIK_PENG and weaveItem.CenterCard == getData then 
                local tabAction = {}
                tabAction.Type = type
                tabAction.CardData = getData
                tabAction.Provider = weaveItem.Provider     --加杠的提供者是碰的那个
                self.tabUserAction[#self.tabUserAction + 1] = tabAction
            end
        end
      
    elseif type == WIKTYPE.WIK_DU then
        for i = 1, PAICONST.MAX_INDEX do 
			if self.tabCbCardIndex[i] == 3 then 
				local val = MjLogic:IndexToVal(i)
                local tabAction = {}
                tabAction.Type = WIKTYPE.WIK_JIAGANG   --还是按加杠算
                tabAction.CardData = val
                if self.tabFrame.tabJiang[1] == val or self.tabFrame.tabJiang[2] == val then 
                    self.tabUserAction[#self.tabUserAction + 1] = tabAction
                    print('************du getData is ', val)
                end
                break
            end
		end
	end  
end

function ChairAction:CanPeng(getData, provider)       --还没有加该张牌
    --if self:IsLouPeng(getData) then return false end         --漏碰
	local index = MjLogic:ValToIndex(getData)
	local num = self.tabCbCardIndex[index]
	local tabAction = {}
	tabAction.CardData = getData
    tabAction.Provider = provider
	if num >= 2 then 
		tabAction.Type = WIKTYPE.WIK_PENG
		self.tabUserAction[#self.tabUserAction + 1] = tabAction
		return true
	end
	return false
end

function ChairAction:CanChi(getData, provider)       --还没有加该张牌
    if not self.tabFrame.CanChi then return false end
    if getData&0xF0 == 0x30 then return false end    --风
	local index = MjLogic:ValToIndex(getData)
    local tabChi = {}
    if (getData&0x0F > 2) and self.tabCbCardIndex[index - 2] > 0 and self.tabCbCardIndex[index - 1] > 0 then
       local chi = {b = getData - 2, a = getData - 1}
       tabChi[#tabChi + 1] = chi
    end
    
    if (getData&0x0F > 1 and getData&0x0F < 9) and self.tabCbCardIndex[index - 1] > 0 and self.tabCbCardIndex[index + 1] > 0 then
       local chi = {b = getData - 1, a = getData + 1}
       tabChi[#tabChi + 1] = chi
    end
    
    if (getData&0x0F < 8) and self.tabCbCardIndex[index + 1] > 0 and self.tabCbCardIndex[index + 2] > 0 then
        local chi = {b = getData + 1, a = getData + 2}
        tabChi[#tabChi + 1] = chi
    end
    
	if #tabChi > 0 then 
        local tabAction = {}
        tabAction.CardData = getData
        tabAction.Provider = provider
		tabAction.Type = WIKTYPE.WIK_LINE
        tabAction.tabChi = tabChi
		self.tabUserAction[#self.tabUserAction + 1] = tabAction
		return true
	end
	return false
end

function ChairAction:SendOperateHint()	
    if #self.tabUserAction > 0 then     
        local msg = self.tabUserAction:GetPackString()
        local protol = CMD.Sub_GameSvrToClient_TableModle_CanPengOrJieGang
        if hasHU then protol = CMD.Sub_GameSvrToClient_TableModle_CanDianPaoHu end
        self:SendDataInLua(protol, msg)
    end
end

function ChairAction:DoHu(getCardData)
	local bHu, huType, fan = false, 0, 0
    local provider = -1

    bHu, huType, fan = self:CheckHu(getCardData)
    local tabAction = self:CouldOperate(WIKTYPE.WIK_HU, getCardData)
    if bHu then provider = tabAction.Provider self.tabUserAction:Reset() end
	if bHu then 
		self.HuType = huType
		self.HuFan = fan
	end
	return bHu, huType, fan, provider
end

function ChairAction:DoActionReq(act, centerCard, cardBef, cardAft)
    local tabAction = self:CouldOperate(act.Type, centerCard)
	if tabAction then 
        print('***********ChairAction:DoActionReq could')
        self.tabUserAction:Reset()
        if self.tabFrame:WaitForOtherActs(self, act.Type, centerCard, cardBef, cardAft, tabAction.Provider) then return false end
        local bDone = act.Func(self, tabAction, centerCard, cardBef, cardAft)
		return bDone and tabAction.Provider   --true and 1 == 1  会返回Provider，其中在DoAnGang中会设置其Provider
	else print('***********ChairAction:DoActionReq could not') return nil end
end

function ChairAction:DoDelayAction(type, tabCardData, provider)
    if type ~= WIKTYPE.WIK_HU then 
        self:DoAction(type, tabCardData, provider)
        self.tabFrame:DoActionCmd(type, self, provider, tabCardData[1], tabCardData[2] or 0, tabCardData[3] or 0)
        self.tabFrame:SetNextUser()
        if type == WIKTYPE.WIK_JIAGANG then 
            self.tabFrame:DispatchCard(self, type)
        end
    else 
        local bHu, huType, fan, prid = self:DoHu(tabCardData[1])
        if bHu then
            self.tabFrame:DoHuCmd(self, prid, tabCardData[1], huType, fan)
        end
    end
end

function ChairAction:DoPeng(tabAction, centerCard)
	return self:DoAction(WIKTYPE.WIK_PENG, {centerCard}, tabAction.Provider)
end

function ChairAction:DoChi(tabAction, centerCard, cardBef, cardAft)
    if self.tabFrame:DoOthersHigherAct(self, WIKTYPE.WIK_LINE) then 
        if self.tabUserAction then 
            self.tabUserAction:Reset() 
        end
        self.tabToDo = nil
        return false
    end
    
    local index1 = MjLogic:ValToIndex(cardBef)
    local index2 = MjLogic:ValToIndex(cardAft)
    self.tabCbCardIndex[index1] = self.tabCbCardIndex[index1] - 1
    self.tabCbCardIndex[index2] = self.tabCbCardIndex[index2] - 1
	self:ResetLou()
	local weaveItem = {}
	weaveItem.CenterCard = centerCard
    weaveItem.Bef = cardBef
    weaveItem.Aft = cardAft
	weaveItem.Provider = tabAction.Provider;
	weaveItem.Kind = WIKTYPE.WIK_LINE
	table.insert(self.tabWeaveItem, weaveItem) 
    
	if self.tabUserAction then 
		self.tabUserAction:Reset() 
	end
    for chair in self.tabFrame:ChairIterator() do 
       chair.tabToDo = nil     --动作都执行了,每个延迟的就清空
    end
    return true
end

function ChairAction:DoJieGang(tabAction, centerCard)
	self:DoAction(WIKTYPE.WIK_JIEGANG, {centerCard}, tabAction.Provider)
    self:UpdataTingData()
    self.LianGang = 1
    return true
end

function ChairAction:DoJiaGang(tabAction, centerCard)
    print('$$$$$$$$$$du')
    function DoRealJiaGang(tabAction, centerCard)
        self:DoAction(WIKTYPE.WIK_JIAGANG, {centerCard}, tabAction.Provider)
        self:UpdataTingData()
        self.LianGang = (self.LianGang or 0) + 1 
        return true
    end
    
    function DoDuGang(tabAction, centerCard)  --笃
        tabAction.Provider = self.UserChairID
        self:DoAction(WIKTYPE.WIK_DU + 1, {centerCard}, tabAction.Provider)
        self:UpdataTingData()
        self.LianGang = (self.LianGang or 0) + 1 
        return true
    end
    if centerCard ~= self.tabFrame.tabJiang[1] and centerCard ~= self.tabFrame.tabJiang[2] then  --笃不需要摸牌
        print('*******DoJiaGang  real')
        return DoRealJiaGang(tabAction, centerCard)
    else
        print('*******DoJiaGang du')
        return DoDuGang(tabAction, centerCard)
    end
end

function ChairAction:DoAnGang(tabAction, centerCard)
    tabAction.Provider = self.UserChairID
	self:DoAction(WIKTYPE.WIK_ANGANG, {centerCard})
    self:UpdataTingData()
    self.LianGang = (self.LianGang or 0) + 1
    return true
end

function ChairAction:DoAction(type, cardData, provider)
    local centerCard = cardData[1]
	local valIndex = MjLogic:ValToIndex(centerCard)
	local numToMinus = 0
    local scoreType 
	if type == WIKTYPE.WIK_PENG then
        numToMinus = 2 
        scoreType = 'peng'
	elseif type == WIKTYPE.WIK_JIEGANG then
        numToMinus = 3 
        scoreType = 'minggang'
	elseif type == WIKTYPE.WIK_JIAGANG then 
        numToMinus = 1
        scoreType = 'jiagang'
	elseif type == WIKTYPE.WIK_ANGANG then 
        numToMinus = 4 
        scoreType = 'angang'
    elseif type == (WIKTYPE.WIK_DU + 1) then 
        numToMinus = 3 
        scoreType = 'dugang'
	else 
        numToMinus = 0 
    end
	self.tabCbCardIndex[valIndex] = self.tabCbCardIndex[valIndex] - numToMinus
	self:ResetLou()
	local weaveItem = {}
	weaveItem.CenterCard = centerCard
	weaveItem.Provider = provider;
	weaveItem.Kind = type
    weaveItem.ScoreKind = scoreType
    if type == WIKTYPE.WIK_JIAGANG then    --如果是加杠，那么就替换表里面的碰
        for k, v in pairs(self.tabWeaveItem) do
            if v.CenterCard == centerCard then 
                self.tabWeaveItem[k] = weaveItem
                break
            end
        end
    else
        table.insert(self.tabWeaveItem, weaveItem)
    end
    
    if self.tabUserAction then 
		self.tabUserAction:Reset() 
	end
    for chair in self.tabFrame:ChairIterator() do 
       chair.tabToDo = nil     --动作都执行了,每个延迟的就清空
    end
    return true    
end

function ChairAction:ResetLou()
    self.LouHu = false
    self.LouPeng = {}
end

function ChairAction:CouldOperate(type, centerCard)
    local useAct = nil
	for i = 1, #self.tabUserAction do
		if self.tabUserAction[i].Type == type and self.tabUserAction[i].CardData == centerCard then
            useAct = self.tabUserAction[i]
			break
		end
	end
	return useAct
end

function ChairAction:CancelActionReq(type)     --有可能已经取消,要防止重复
    local bOk, centerCard = self:CancelAction(type)
	if bOk then
        self:SendDataInLua(self.CANCELCMD[type])
        if type == WIKTYPE.WIK_HU then         --漏胡
            self.LouHu = true
        elseif type == WIKTYPE.WIK_PENG then
            self.LouPeng = self.LouPeng or {}
            if centerCard then self.LouPeng[centerCard] = true end
        end
        skynet.error('Chair Id '..self.UserChairID..' Cancel type is'..type..' Card is '..centerCard)
		return true
	end
	return false
end

function ChairAction:CancelAction(type)
	local bHas = false
    local centerCard
	for i = 1, #self.tabUserAction do
		if self.tabUserAction[i].Type == type then
			bHas = true
            centerCard = self.tabUserAction[i].CardData
			self.tabUserAction:Reset()
			break
		end
	end
	return bHas, centerCard
end

function ChairAction:OnLiuJu()
	
end

function ChairAction:CalTotalHuShu(huData)     --计算胡数
    local tabKsq = {ksq = {k = 0,s = 0,q = 0}}
    if self.DoneHu then  
        if MjLogic:GetHandCardNum(self.tabCbCardIndex) % 3 == 1 then 
            local index = MjLogic:ValToIndex(huData.HuCardData)
            self.tabCbCardIndex[index] = self.tabCbCardIndex[index] + 1
        end 
        local tabWan, tabTiao, tabTong, tabZi = MjLogic:ParsePaiToWTTZ(self.tabCbCardIndex)
        local tabWTTZ = {tabWan, tabTiao, tabTong, tabZi}
        MjLogic:ProcessOneColor(tabWTTZ[1], true, tabKsq)
        MjLogic:ProcessOneColor(tabWTTZ[2], true, tabKsq)
        MjLogic:ProcessOneColor(tabWTTZ[3], true, tabKsq)
        MjLogic:ProcessZiPai(tabWTTZ[4], true, tabKsq)
        
        skynet.error(string.format('CaltotalHuShu id is %d, In hand, ke is %d, shun is %d', self.UserChairID, tabKsq.ksq.k, tabKsq.ksq.s))
        local strKeVal = 'kv is '
        for _, v in pairs(tabKsq.ksq.kv or {}) do
            strKeVal = strKeVal..string.format(' %0x', v)
        end
        skynet.error(strKeVal)
        
        local strSVal = 'sv is '
        for _, v in pairs(tabKsq.ksq.sv or {}) do
            strSVal = strSVal..string.format(' %0x', v)
        end
        skynet.error(strSVal)
        skynet.error(string.format('jiang is %0x', tabKsq.ksq.jv[1]))
     
    end
    
    function GetPaiName(card)
        local retStr = ''
        if card == 0x31 then retStr = '千字' 
        elseif card == 0x32 then retStr = '红花'
        elseif card == 0x33 then retStr = '白花'
        elseif card >= 0x40 then retStr = '百搭'
        else
            local val = (card & 0x0F)
            local col = (card & 0xF0)
            local wttzName = {[0]='万',[0x10]='条',[0x20]='饼'}
            retStr = string.format('%d%s',val, wttzName[col])
        end
        return retStr
    end
    
    function GetWIKTypeName(type)
        local retStr = ''
        if type == WIKTYPE.WIK_PENG then 
            retStr = '碰'
        elseif type == WIKTYPE.WIK_JIEGANG then
            retStr = '明杠'
        elseif type == WIKTYPE.WIK_JIAGANG then 
            retStr = '笃'
        elseif type == WIKTYPE.WIK_ANGANG then 
            retStr = '暗杠'
        elseif type == (WIKTYPE.WIK_DU + 1) then 
            retStr = '笃'
        end
        return retStr
    end
    
    local ScoreConfig = require "calscore"
    
    function GetOutHandCardHuShu()    --亮出来牌的胡数
        local huShu = 0
        local jiang
        local ScoreConfigGetHuShu
        if Config.FanJiangNum == 1 then 
            jiang = self.tabFrame.tabJiang[1]
            ScoreConfigGetHuShu = ScoreConfig.GetHuShu1
        elseif Config.FanJiangNum == 2 then
            jiang = self.tabFrame.tabJiang
            ScoreConfigGetHuShu = ScoreConfig.GetHuShu2
        end
        local tip = ''
        for _, v in pairs(self.tabLiaoLong or {}) do        --计算撂龙的分
            local hu = ScoreConfigGetHuShu('liao', jiang, v) 
            huShu = huShu + hu
            tip = tip..string.format('%s撂龙%d胡 ',GetPaiName(v), hu)
        end
        
        for _, v in pairs(self.tabWeaveItem or {}) do  
            local hu = ScoreConfigGetHuShu(v.ScoreKind, jiang, v.CenterCard) 
            huShu = huShu + hu
            tip = tip..string.format('%s%s%d胡 ',GetWIKTypeName(v.Kind), GetPaiName(v.CenterCard), hu)
        end
        
        return huShu, tip
    end
    
    function GetXiPaiHuShu()
        local huShu = 0
        local numXipai = #self.tabXiPai
        if Config.FanJiangNum == 1 then 
            local jiang = self.tabFrame.tabJiang[1]
            local j
            if jiang >= 0x40 then j = 0x40 end
            huShu = ScoreConfig.GetXiPaiHuShu(1, j, numXipai)
        elseif Config.FanJiangNum == 2 then
            huShu = ScoreConfig.GetXiPaiHuShu(2, self.tabFrame.tabJiang, numXipai)
        end
        local retStr = ''
        if huShu > 0 then retStr = string.format('百搭%d个%d胡 ', numXipai, huShu) end
        return huShu, retStr
    end
    
    function GetInHandCardHuShu()    --手上牌的胡数
        local huShu = 0
        local jiang = self.tabFrame.tabJiang[1]
        local retStr = ''
        for i = 1, PAICONST.MAX_INDEX do 
			if self.tabCbCardIndex[i] >= 3 then 
                local val = MjLogic:IndexToVal(i)
                if Config.FanJiangNum == 1 then 
                    local hu = ScoreConfig.GetHuShuInHand1(jiang, val)
                    retStr = retStr..string.format('暗刻%s%d胡 ', GetPaiName(val), hu)
                    huShu = huShu + hu
                elseif Config.FanJiangNum == 2 then 
                    local hu = ScoreConfig.GetHuShuInHand2(self.tabFrame.tabJiang, val)
                    huShu = huShu + hu
                    retStr = retStr..string.format('暗刻%s%d胡 ', GetPaiName(val), hu)
                end
            end
        end
        return huShu, retStr
    end
    local huOut, tipOut = GetOutHandCardHuShu()
    local huIn, tipIn = GetInHandCardHuShu()
    local huXi, tipXi = GetXiPaiHuShu()
    local huFan, tipFan = self:GetFanHuShu(huData, tabKsq.ksq)   --额外的胡数
    local huBei, tipBei = self:GetBeiShu(huData, tabKsq.ksq)
    local huShu = huOut + huIn + huXi + huFan 
    huShu = huShu * huBei
    self.HuShu = huShu
    self.ResultMsg = tipOut..tipIn..tipXi..tipFan..tipBei
    return huShu
end

function ChairAction:GetFanHuShu(huData, ksq)     --只要不是翻倍的分数

    function IsZiMo()
        return huData.ZiMo
    end
    
    function IsPiaoHu()     --手牌要么是刻子，要么是文钱
        for _, v in pairs(ksq.sv or {}) do
            if v & 0x0F ~= 2 then return false end    --不是文钱就返回了，其他的情况就是符号的
        end
        return true
    end
    
    function IsQingHu()   --全是顺子
        if #self.tabWeaveItem > 0 then return false  --没有吃，故有weav肯定就非全顺子
        else 
            return ksq.k == 0     --没有刻子，肯定全是顺子
        end
        return true
    end
    
    function IsTaiZiHu()
        return not IsQingHu() and not IsPiaoHu()
    end
    
    function IsYaZi() 
        for _, v in pairs(ksq.sv or {}) do
            if v == huData.HuCardData then return true end    --胡卡张
        end
        return false
    end
    
    function IsTuoWei()
        for _, v in pairs(ksq.sv or {}) do
            if ((v & 0x0F) == 2 and (huData.HuCardData & 0x0F) == 3) or   --123,胡3 789胡7
               ((v & 0x0F) == 8 and (huData.HuCardData & 0x0F) == 7) then
               return true
            end
        end
        return false
    end
    
    function IsDiaoTou()    --吊头，单吊
        if ksq.jv[1] == huData.HuCardData then return true end
        return false
    end
    
    local tabHuShu = {
        {fn = IsQingHu,   huShu = 100, jiang = 1|2, shouldHu = true, tip='清胡100胡'},
        {fn = IsTaiZiHu,  huShu = 10,  jiang = 1|2, shouldHu = true, tip='塌子胡10胡'},
        {fn = IsYaZi,     huShu = 10,  jiang = 1|2, shouldHu = true, tip='丫子10胡'},
        {fn = IsTuoWei,   huShu = 10,  jiang = 1|2, shouldHu = true, tip='拖尾10胡'},
        {fn = IsDiaoTou,  huShu = 10,  jiang = 1|2, shouldHu = true, tip='吊头10胡'},
        {fn = IsZiMo,     huShu = 10,  jiang = 1|2, shouldHu = true, tip='自摸10胡'},
    }
    
    local huShu = 0
    local huTip = ''
    for k, v in pairs(tabHuShu) do 
        if Config.FanJiangNum & v.jiang ~= 0 then   --将
            local doit = (not v.shouldHu) or (v.shouldHu and self.DoneHu)  --不必胡或者胡了需胡
            if doit then
                if v.fn() then
                    huShu = huShu + v.huShu 
                    huTip = huTip..string.format('%s ', v.tip)
                end
            end
        end
    end
    
    function GetWenQian()  --文钱 需胡
        local wenqian = {20, 50, 100, 200}
        if not self.DoneHu then return 0 end
        local tabWenQian = {self.tabCbCardIndex[0x21], self.tabCbCardIndex[0x22], self.tabCbCardIndex[0x23]}
        table.sort(tabWenQian)
        local wqNum = tabWenQian[1] or 0  --文钱的个数
        if wqNum ~= 0 then huTip = huTip..string.format('文钱%d胡', wenqian[wqNum] or 0) end
        return wenqian[wqNum] or 0
    end
    
    huShu = huShu + GetWenQian()     --文钱
    return huShu, huTip
end

function ChairAction:GetBeiShu(huData, ksq)    --倍数

    function IsPiaoHu()     --手牌要么是刻子，要么是文钱
        for _, v in pairs(ksq.sv or {}) do
            if v & 0x0F ~= 2 then return false end    --不是文钱就返回了，其他的情况就是符号的
        end
        return true
    end

    function IsTianHu()  --天胡
        if self.tabFrame.Banker == self.UserChairID and #self.tabCbOutCard == 0 then
            return true 
        else return false end
    end
    
    function IsHaiDiLao()  --海底捞
        return self.tabFrame.LeftCardCount == 0
    end
    
    function IsQiongHen()   --穷恨 单将 需胡
        return not self.HasDispatchXiPai
    end
    
    function IsSanLao()    --三老
        local lao = 0
        for _, v in pairs(self.tabWeaveItem or {}) do
            if v.CenterCard >= 0x31 and v.CenterCard <= 0x33 then lao = lao + 1 end
        end
        local qian = MjLogic:ValToIndex(0x31)
        for i = 0, 2 do 
            if self.tabCbCardIndex[qian + i] >= 3 then lao = lao + 1 end
        end
        return lao == 3
    end
    
    function IsShuangLong()   --双龙  
        local num = 0
        for _, v in pairs(self.tabWeaveItem or {}) do  
            if v.Kind == WIKTYPE.WIK_ANGANG then
                num = num + 1
            end
        end
        
        for _, v in pairs(self.tabLiaoLong or {}) do        --计算撂龙,包含了5个喜牌的情况
            num = num + 1
        end
        
        for i = 1, PAICONST.MAX_INDEX do 
			if self.tabCbCardIndex[i] == 4 then num = num + 1 end
        end
        return num >= 2 
    end
    
    function IsErLongXiZhu()   --二龙戏珠 需胡
        local erLongNum = 0
        if (huData.HuCardData & 0x0F) == 2 then 
            for _, v in pairs(ksq.sv or {}) do
                if v == huData.HuCardData then
                    erLongNum = erLongNum + 1
                end    
            end
        end
        return erLongNum == 2
    end
    
    function IsQiongQiongHen()   --穷穷恨，单将 需胡
        if self.tabFrame.tabJiang[1] & 0xF0 == 0x40 then 
            if not self.HasDispatchXiPai then return true end
        end
        return false
    end
    
    function IsYiTouHu()   --一头胡 需胡
        if ksq.k == 0 then    --没有刻子
            if true then return true end
        end
        return false
    end
    
    function Is19Hui()    --19会
        local tabYiJiu = {[1] = {val = 1, num = 0}, [9] = {val = 9, num = 0}}
        local ret = 0
        for k, yijiu in pairs(tabYiJiu) do
            for _, v in pairs(self.tabWeaveItem or {}) do
                if (v.CenterCard & 0x0F) == yijiu.val then
                    tabYiJiu[k].num = tabYiJiu[k].num + 1 
                end
            end
            for _, v in pairs(ksq.kv or {}) do
                if (v & 0x0F) == yijiu.val then 
                    tabYiJiu[k].num = tabYiJiu[k].num + 1 
                end    
            end
            if tabYiJiu[k].num >= 3 then ret = ret + 1 end
        end
        return (ret > 0), ret, string.format('1,9会%d倍 ', ret * 2)   --一个就是2倍
    end
    
    local tabBeiShu = {
        {fn = IsPiaoHu,        bei = 2, jiang = 1|2, shouldHu = true, tip='漂胡2倍'},
        {fn = IsTianHu,        bei = 2, jiang = 1|2, shouldHu = true, tip='天胡2倍'},
        {fn = IsHaiDiLao,      bei = 2, jiang = 1|2, shouldHu = true, tip='海底捞2倍'},
        {fn = IsQiongHen,      bei = 2, jiang = 1,   shouldHu = true, tip='穷恨2倍'},
        {fn = IsSanLao,        bei = 2, jiang = 1|2, shouldHu = false, tip='三老齐会2倍'},
        {fn = IsShuangLong,    bei = 2, jiang = 1,   shouldHu = false, tip='双龙2倍'},
        {fn = IsErLongXiZhu,   bei = 2, jiang = 1,   shouldHu = true, tip='二龙戏珠2倍'},
        {fn = IsQiongQiongHen, bei = 4, jiang = 1,   shouldHu = true, tip='穷穷恨2倍'},
        {fn = IsYiTouHu,       bei = 2, jiang = 1,   shouldHu = true, tip='一头胡2倍'},
        {fn = Is19Hui,         bei = 2, jiang = 1,   shouldHu = false, tip='1,9会2倍'}
    }
    local bei = 0
    local huTip = ''
    for k, v in pairs(tabBeiShu) do 
        if Config.FanJiangNum & v.jiang ~= 0 then   --将
            local doit = (not v.shouldHu) or (v.shouldHu and self.DoneHu)  --不必胡或者胡了需胡
            if doit then
                local bOk, ret, tip = v.fn()    --有的会返回倍数，提示，而不用默认的
                if bOk then 
                    bei = bei + (ret or v.bei)
                    huTip = huTip..(tip or string.format('%s ', v.tip))
                end
            end
        end
    end
    if bei == 0 then bei = 1 end
    return bei, huTip
end

function ChairAction:ConcludeGame(huData)
	self.standCard = {}     --站立的牌
	local nStand = 0
	for i = 1, #self.tabCbCardIndex do 
		local indexNum = self.tabCbCardIndex[i]
		for j = 1, indexNum do
			nStand = nStand + 1
			self.standCard[nStand] = MjLogic:IndexToVal(i) 	
		end
	end
	
    --if huData.LiuJu then self.ResultMsg = "流局" end
end

function ChairAction:GetFanWaiFan()
    function IsMengQing()
        if #self.tabWeaveItem == 0 then return true end
        for _, v in pairs(self.tabWeaveItem) do
            if v.Kind == WIKTYPE.WIK_LINE then return false 
            elseif v.Kind == WIKTYPE.WIK_PENG then return false 
            elseif v.Kind == WIKTYPE.WIK_JIAGANG then return false 
            elseif v.Kind == WIKTYPE.WIK_JIEGANG then return false 
            end
        end
        return true
    end
    
    function IsTianHu()
        if self.tabFrame.Banker == self.UserChairID and #self.tabCbOutCard == 0 then return true else return false end
    end
    function IsDiHu()
        for chair in self.tabFrame:ChairIterator() do
            if chair.UserChairID == self.tabFrame.Banker then 
                if #chair.tabCbOutCard ~= 1 then return false end
            else
                if chair.UserChairID ~= 0 then return false end
            end
        end
        return true
    end
	function IsQuanQiuRen()
        if #self.tabWeaveItem == 4 then 
            for _, v in pairs(self.tabWeaveItem) do
                if v.Kind == WIKTYPE.WIK_ANGANG then return false end
            end
            return true
        else return false end
    end
    local fan = 0
    if IsMengQing() then skynet.error('Chair Id '..self.UserChairID..' Hu Meng Qing') fan=fan|FANWAIFAN.MENQINIG end
    if IsTianHu() then skynet.error('Chair Id '..self.UserChairID..' Hu TianHu') fan=fan|FANWAIFAN.TIANHU end
    if IsDiHu() then skynet.error('Chair Id '..self.UserChairID..' Hu DiHu') fan=fan|FANWAIFAN.DIHU end
    if IsQuanQiuRen() then skynet.error('Chair Id '..self.UserChairID..' Hu QuanQiuRen') fan=fan|FANWAIFAN.QUANQIUREN end
    return fan
end

function ChairAction:GetStandCard()
    local standCard = {}
    local nStand = 0
    for i = 1, #self.tabCbCardIndex do 
        local num = self.tabCbCardIndex[i]
        for j = 1, num do
            nStand = nStand + 1
            standCard[nStand] = MjLogic:IndexToVal(i) 	
        end
    end
    self.standCard = standCard
    return standCard
end

function ChairAction:SendMeOfflineBackData(index, wUserChairId)
    local bufData = ''
	if index == 'standCard' then
        local str = ''
        local standCard = self:GetStandCard()
		for i = 1, TABLECONST.NUM_HANDFULL do   --23个
			local val = standCard[i]
            bufData = bufData..string.pack('B', val or 0)
            str = str..string.format('%0x ', val or 0)
		end
        
	elseif index == 'weaveItem' then 
		local totalW = 0
        for i = 1, TABLECONST.MAXWEAVCOUNT do   
            local weave = self.tabWeaveItem[i]
            if weave then 
                totalW = totalW + 1
                bufData = bufData..string.pack('BBI2BB', weave.Kind, weave.CenterCard, weave.Provider or 255, weave.Bef or 0, weave.Aft or 0)        
            else 
                bufData = bufData..BufTool.WriteOffset(6)
            end
		end
        
	elseif index == 'outCard' then 
        if not self.tabCbOutCard then 
            bufData = bufData..BufTool.WriteOffset(TABLECONST.MAXOUTCARDCOUNT)
        else 
            for i = 1, TABLECONST.MAXOUTCARDCOUNT do
                bufData = bufData..string.pack('B', self.tabCbOutCard[i] or 0)
            end
        end

	elseif index == 'tingData' then
        if not self.tabTingCardData or not self.tabTingCardData.val then 
            bufData = bufData..BufTool.WriteOffset(TABLECONST.MAX_TING)
        else
            for i = 1, TABLECONST.MAX_TING do                 
                local vt = self.tabTingCardData.val[i]
                bufData = bufData..string.pack('B', vt or 0)
            end
        end	
	end
    return bufData
end
